#ifndef _CCGENGPU_H_
#define _CCGENGPU_H_

#ifdef USE_GPU

#include <d3d11.h>
#include <tbb/compat/thread> //for std::thread
#include <tbb/concurrent_queue.h>
#include <tbb/mutex.h>
#include <map>

#include "CCGen.h"
#include "CJobDispatcher.h"

enum EGpuHandlerStatus
{
	eGHS_invalid,
	eGHS_failed,
	eGHS_valid,
};

enum EGpuThreadMessageCode
{
	eGMC_filter_level,
	eGMC_filter_cubemap,
	eGMC_create_tapdir_lut,
	eGMC_create_filter_extents_lut,
	eGMC_destroy_thread
};

struct SGpuThreadMessage
{
	EGpuThreadMessageCode code;
	void *data;
};

struct SGpuFilterLevelJob
{
	SFilterSurfaceJob job;
	STapdirLUT *tapdirLut;
	SFilterExtentsLUT *filterExtentsLut;
};

struct SGpuFilterCubemapJob
{
	SGpuFilterLevelJob *filterJobs;
	SCubeFace inputFaces[6];
	SFilterState *filterState;
	const SFilterStateData *filterStateData;
	int jobCount;
	SFilterJobInternal *parentJob;
	volatile unsigned int *internalCounter;

	~SGpuFilterCubemapJob()
	{
		SAFE_DELETE_ARRAY(filterJobs);
	}
};

struct STexture
{
	ID3D11Texture2D *texture;
	ID3D11ShaderResourceView *textureSRV;
	ID3D11UnorderedAccessView *textureUAV;

	EGpuHandlerStatus status;

	STexture()
	{
		status = eGHS_invalid;
		texture = nullptr;
		textureSRV = nullptr;
		textureUAV = nullptr;
	}

	~STexture()
	{
		SAFE_RELEASE(texture);
		SAFE_RELEASE(textureSRV);
		SAFE_RELEASE(textureUAV);
	}
};


class CCGenGpu
{
	struct SFilterTextures
	{
		STexture srcTexture;
		STexture *dstTextures;
		STexture *stagingTextures;

		~SFilterTextures()
		{
			SAFE_DELETE_ARRAY(dstTextures);
			SAFE_DELETE_ARRAY(stagingTextures);
		}
	};

	tbb::concurrent_queue<SGpuThreadMessage> message_queue;

	ID3D11Device *d3dDevice;
	ID3D11DeviceContext *d3dDeviceContext;
	ID3D11ComputeShader *computeShader;
	ID3D11Buffer *filterConstantBuffer;
	EGpuHandlerStatus gpuStatus;
	tbb::tbb_thread *gpuThread;	
	std::map<int, SFilterTextures*> filterTextures;

	CJobDispatcher *dispatcher;

public:

#ifdef ENABLE_GRAPHICS_DEBUGGING
	IDXGISwapChain *swapChain;
#endif

	CCGenGpu(CJobDispatcher *disp);
	~CCGenGpu();
	bool EnableGpu();
	bool IsGpuEnabled(){return gpuStatus == eGHS_valid;}
	void SendMessage(const SGpuThreadMessage& msg);
	void CreateTapdirLUT( TLUTData<Vec4> *initialData, unsigned int mipCount, STexture **outTexture );
	void CreateTapdirLUT_imp( TLUTData<Vec4> *initialData, unsigned int mipCount, STexture **outTexture );
	void CreateFilterExtentLUT( TLUTData<SFilterExtentsLUT::FilterExtent> *initialData, unsigned int mipCount, STexture **outTexture );
	void CreateFilterExtentLUT_imp( TLUTData<SFilterExtentsLUT::FilterExtent> *initialData, unsigned int mipCount, STexture **outTexture );
	void GetFilterTextures(const SFilterState *filterState, const SFilterStateData *filterStateData, STexture **outDstTexture, STexture **outSrcTexture, STexture **outStagingTexture );
	void WaitForAll();
	static void _GPUThreadEntry(void *ptr);
};

#endif

#endif